import { motion } from "motion/react"
import styled from "@emotion/styled"
import {
    //
    useForm as __useForm,
    useFormContext as __useFormContext,
    FormProvider as __FormProvider,
    FieldPath as __FieldPath,
    UseFormReturn as __UseFormReturn,
    RegisterOptions as __RegisterOptions,
    UseFormRegisterReturn as __UseFormRegisterReturn,
    FieldErrors as __FieldErrors,
    FieldValues as __FieldValues,
} from "react-hook-form"

const ErrorWrapperStyled = styled(motion.div)`
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8rem;
`

function createForm<T extends __FieldValues>() {
    const useForm = __useForm<T>
    const useFormContext = __useFormContext<T>
    const FormProvider = __FormProvider<T>

    type BaseItemProps<K extends __FieldPath<T>> = {
        label: string
        field: K
        render: (props: {
            label: string
            methods: __UseFormReturn<T>
            registration: __UseFormRegisterReturn<K>
            error: __FieldErrors<T>[K]
        }) => React.ReactNode
        options?: __RegisterOptions<T, K>
    }

    function BaseItem<K extends __FieldPath<T>>(props: BaseItemProps<K>) {
        const {
            //
            label: _label,
            field: _field,
            options: _options,
            render: _render,
        } = props
        const context = useFormContext()
        const registration = context.register(_field, _options)
        const error = context.formState.errors[_field]
        return _render({
            methods: context,
            registration,
            error,
            label: _label,
        })
    }

    function ErrorMessage({
        render,
    }: {
        render: (props: { error: __FieldErrors<T> }) => React.ReactNode
    }) {
        const context = useFormContext()
        const error = context.formState.errors
        return render({
            error,
        })
    }

    type ErrorWrapperProps = Omit<ExtractStyledProps<typeof ErrorWrapperStyled>, "children"> & {
        field: __FieldPath<T>
        render: (props: { error: __FieldErrors<T>[__FieldPath<T>] }) => React.ReactNode
        children: React.ReactNode
    }

    function ErrorWrapper({ children, field, render, ...props }: ErrorWrapperProps) {
        const context = useFormContext()
        const error = context.formState.errors[field]
        return (
            <ErrorWrapperStyled {...props}>
                {children}
                {render({
                    error,
                })}
            </ErrorWrapperStyled>
        )
    }

    type FormValues = T

    return {
        useForm,
        useFormContext,
        FormProvider,
        BaseItem,
        ErrorWrapper,
        ErrorMessage,
        _type: {
            FormValues: {} as FormValues,
        },
    }
}

export default createForm
